package com.zshan.clinic.admin.service.medical;


import com.zshan.clinic.admin.entity.medical.order.charge.ChargeOrderBO;
import com.zshan.clinic.admin.entity.medical.schedule.DoctorRemain;
import com.zshan.clinic.admin.entity.medical.schedule.TimeRange;
import com.zshan.clinic.admin.entity.vo.*;
import com.zshan.clinic.admin.entity.vo.print.ClinicRegisterPrintVo;
import com.zshan.clinic.admin.producer.AutoCheckinProducer;
import com.zshan.clinic.admin.mapper.medical.SpecRegisterMapper;
import com.zshan.clinic.admin.service.clinic.ClinicDeptService;
import com.zshan.clinic.admin.service.config.PrintConfigService;
import com.zshan.clinic.admin.service.patient.ClinicPatientService;
import com.zshan.clinic.admin.task.AsyncTaskService;
import com.zshan.clinic.admin.util.RegUtil;
import com.zshan.clinic.common.constant.CommonConstant;
import com.zshan.clinic.common.enums.*;
import com.zshan.clinic.common.exception.BusinessFailException;
import com.zshan.clinic.common.util.page.PageInfo;
import com.zshan.clinic.common.util.page.PageUtils;
import com.zshan.clinic.common.util.redis.RedisUtil;
import com.zshan.clinic.common.util.string.StringUtil;
import com.zshan.clinic.database.dao.ClinicRegisterMapper;
import com.zshan.clinic.database.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 挂号
 */
@Service
@Slf4j
public class ClinicRegisterService {

    @Autowired
    private ClinicRegisterMapper clinicRegisterMapper;

    @Autowired
    private ClinicPatientService patientService;

    @Autowired
    private SpecRegisterMapper specRegisterMapper;

    @Autowired
    private ChargeOrderService chargeOrderService;

    @Autowired
    private ClinicDeptService clinicDeptService;

    @Autowired
    private AsyncTaskService asyncTaskService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private PrintConfigService printConfigService;

    /**
     * 打印挂号单
     * @param registerId 挂号ID
     * @return
     */
    public ClinicRegisterPrintVo getRegisterPrint(Long clinicId, Long registerId,String printBy){
        ClinicPrintConfigVo clinicPrintConfig = printConfigService.getConfigByCategoryAndType(clinicId,PrintCategoryEnum.RECEIPT.getValue(),Collections.singletonList(PrintTypeEnum.REGISTRATION_RECEIPT.getValue()));
        if(clinicPrintConfig == null){
            throw new BusinessFailException("打印抬头未设置，请联系管理员处理！");
        }
        ClinicRegisterPrintVo clinicRegisterPrintVo = specRegisterMapper.getRegisterPrintDetail(clinicId,registerId);
        //设置底部信息
        clinicRegisterPrintVo.setPrintBy(printBy);
        clinicRegisterPrintVo.setPrintTime(new Date());
        clinicRegisterPrintVo.setTitle(clinicPrintConfig.getTitle());
        clinicRegisterPrintVo.setAddress(clinicPrintConfig.getAddress());
        clinicRegisterPrintVo.setPhone(clinicPrintConfig.getPhone());
        return clinicRegisterPrintVo;
    }



    public PageInfo<ClinicRegisterPatientVo> getPatientRegList(Long clinicId, Long patientId, LocalDate visitDate, Integer pageNo, Integer pageSize) {
        Long totalCount = specRegisterMapper.getPatientRegCount(clinicId,patientId,visitDate);
        if(StringUtil.isBlank(totalCount)){
            return PageInfo.build();
        }
        List<ClinicRegisterPatientVo> registerList = specRegisterMapper.getPatientRegList(clinicId,patientId,visitDate,PageUtils.getOffset(pageNo,pageSize),pageSize);
        return new PageInfo<>(totalCount,registerList);
    }
    /**
     * 修改挂号单状态为检查中
     * @param registerId
     */
    @Transactional(rollbackFor = Exception.class)
    public void completed(Long registerId) {
        ClinicRegister dbClinicRegister = getRegisterById(registerId);
        if(dbClinicRegister == null){
            return;
        }
        if(RegStatusEnum.COMPLETED.getValue().equals(dbClinicRegister.getRegStatus())){
            log.info("挂号单已经是完诊状态:{}",registerId);
            return;
        }
        dbClinicRegister.setRegStatus(RegStatusEnum.COMPLETED.getValue());
        dbClinicRegister.setUpdateTime(new Date());
        clinicRegisterMapper.updateByPrimaryKeySelective(dbClinicRegister);
    }

//    /**
//     * 修改挂号单状态为检查中
//     * @param registerId
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public void treatment(Long registerId) {
//        ClinicRegister dbClinicRegister = getRegisterById(registerId);
//        if(dbClinicRegister == null){
//            throw new BusinessFailException("挂号不存在");
//        }
//        if(!RegStatusEnum.CHECK_IN.getValue().equals(dbClinicRegister.getRegStatus())){
//            log.info("挂号单状态错误:{}",registerId);
//            return;
//        }
//        dbClinicRegister.setRegStatus(RegStatusEnum.IN_TREATMENT.getValue());
//        dbClinicRegister.setUpdateTime(new Date());
//        clinicRegisterMapper.updateByPrimaryKeySelective(dbClinicRegister);
//    }

    /**
     * 修改挂号单的状态为待诊
     * @param dbClinicRegister
     */
    @Transactional(rollbackFor = Exception.class)
    public void checkIn(ClinicRegister dbClinicRegister) {
        log.info("自动签到修改挂号表的状态:{}",dbClinicRegister);
        if(RegChannelEnum.OUTPATIENT.getValue().equals(dbClinicRegister.getRegChannel())){
            //如果是在门诊直接看诊，就不用叫号了
            return;
        }
        dbClinicRegister.setRegStatus(RegStatusEnum.CHECK_IN.getValue());
        dbClinicRegister.setUpdateTime(new Date());
        clinicRegisterMapper.updateByPrimaryKeySelective(dbClinicRegister);
    }



    /**
     * 查询需要退号的患者列表
     * @param clinicId
     * @param shiftId
     * @param doctorId
     * @param rangeList 需要退号的时间段
     * @return
     */
    public Long getCancelRegisterCount(Long clinicId,Long shiftId, Long doctorId,List<TimeRange> rangeList){
        return specRegisterMapper.getCancelRegisterCount(clinicId,shiftId,doctorId,rangeList);
    }



    /**
     * 查询需要退号的患者列表
     * @param clinicId
     * @param visitDate
     * @param doctorId
     * @param rangeList 需要退号的时间段
     * @return
     */
    public List<ClinicRegisterVo> getCancelRegisterList(Long clinicId,Long doctorId,LocalDate visitDate,List<TimeRange> rangeList){
        return specRegisterMapper.getCancelRegisterList(clinicId,visitDate,doctorId,rangeList);
    }

    /**
     * 退号
     * @param clinicRegister
     */
    @Transactional(rollbackFor = Exception.class)
    public void cancelRegister(ClinicRegister clinicRegister){
        ClinicRegister dbClinicRegister = getRegisterById(clinicRegister.getRegisterId());
        if(dbClinicRegister == null){
            throw new BusinessFailException("挂号记录不存在");
        }
        if(!RegStatusEnum.canRefund(dbClinicRegister.getRegStatus())){
            throw new BusinessFailException("状态不允许");
        }
        dbClinicRegister.setRegStatus(RegStatusEnum.REFUNDED.getValue());
        dbClinicRegister.setPayStatus(PayStatusEnum.CANCELED.getValue());
        dbClinicRegister.setUpdateUserId(clinicRegister.getUpdateUserId());
        dbClinicRegister.setUpdateBy(clinicRegister.getUpdateBy());
        dbClinicRegister.setUpdateTime(new Date());
        clinicRegisterMapper.updateByPrimaryKeySelective(dbClinicRegister);
        if(!StringUtil.isBlank(dbClinicRegister.getOrderId())){
            //处理订单状态为已退
            ChargeOrder chargeOrder = new ChargeOrder();
            chargeOrder.setOrderId(dbClinicRegister.getOrderId());
            chargeOrder.setUpdateUserId(dbClinicRegister.getUpdateUserId());
            chargeOrder.setUpdateBy(dbClinicRegister.getUpdateBy());
            chargeOrderService.refundOrder(chargeOrder);
        }
    }

    /**
     * 预约取号
     * @param register
     */
    @Transactional(rollbackFor = Exception.class)
    public RegSuccessVo pickupRegister(ClinicRegister register){
        ClinicRegister dbClinicRegister = getRegisterById(register.getRegisterId());
        if(dbClinicRegister == null){
            throw new BusinessFailException("挂号记录不存在");
        }
        if(RegMethodEnum.REGISTER_ONSITE.getValue().equals(dbClinicRegister.getRegMethod())){
            throw new BusinessFailException("只能取预约号！");
        }
        if(!RegStatusEnum.RESERVED.getValue().equals(dbClinicRegister.getRegStatus())){
            throw new BusinessFailException("状态不允许");
        }
        if(!dbClinicRegister.getVisitDate().equals(LocalDate.now())){
            throw new BusinessFailException("请就诊日当天前来取号！");
        }
        dbClinicRegister.setRegStatus(RegStatusEnum.PAID_NOT_TAKEN.getValue());
        dbClinicRegister.setUpdateUserId(register.getUpdateUserId());
        dbClinicRegister.setUpdateBy(register.getUpdateBy());
        dbClinicRegister.setUpdateTime(new Date());
        clinicRegisterMapper.updateByPrimaryKeySelective(dbClinicRegister);
        RegSuccessVo regSuccessVo = new RegSuccessVo();
        regSuccessVo.setDeptName(dbClinicRegister.getDeptName());
        regSuccessVo.setDoctorName(dbClinicRegister.getDoctorName());
        regSuccessVo.setVisitStartTime(dbClinicRegister.getVisitStartTime());
        regSuccessVo.setVisitEndTime(dbClinicRegister.getVisitEndTime());
        regSuccessVo.setRegisterId(dbClinicRegister.getRegisterId());
        if(PayStatusEnum.PAID.getValue().equals(dbClinicRegister.getPayStatus())){
            //如果已经支付成功了，支付返回支付结果
            regSuccessVo.setOrderId(dbClinicRegister.getOrderId());
            regSuccessVo.setPayStatus(dbClinicRegister.getPayStatus());
            //模拟签到延迟一分钟加入到排队表
            autoCheckinProducer.submitDelaySeconds(dbClinicRegister.getRegisterId(),60);
        }else {
            if(StringUtil.isBlank(dbClinicRegister.getOrderId())){
                //生成一张挂号收费单
                dbClinicRegister.setCreateUserId(dbClinicRegister.getUpdateUserId());
                dbClinicRegister.setCreateBy(dbClinicRegister.getUpdateBy());
                //生成缴费单同时回写订单ID
                ChargeOrderBO chargeOrder = chargeOrderService.createRegisterOrder(dbClinicRegister);
                dbClinicRegister.setOrderId(chargeOrder.getOrderId());
                dbClinicRegister.setUpdateTime(new Date());
                clinicRegisterMapper.updateByPrimaryKeySelective(dbClinicRegister);
            }
            regSuccessVo.setOrderId(dbClinicRegister.getOrderId());
            regSuccessVo.setPayStatus(PayStatusEnum.ORDERED.getValue());
        }
        //统计诊所今日营收
        StatClinicIncomeDaily statClinicIncomeDaily = new StatClinicIncomeDaily();
        statClinicIncomeDaily.setClinicId(dbClinicRegister.getClinicId());
        statClinicIncomeDaily.setRegCount(CommonConstant.DEFAULT_1);
        asyncTaskService.asyncSaveOrUpdateClinicIncome(statClinicIncomeDaily);
        return regSuccessVo;
    }

    /**
     * 查询挂号列表
     * @param clinicId
     * @param patientName
     * @param deptId
     * @param visitDate
     * @param regStatus
     * @param pageNo
     * @param pageSize
     * @return
     */
    public PageInfo<ClinicRegisterVo> getRegisterList(Long clinicId,String patientName,Long deptId,Long doctorId,LocalDate visitDate,String regStatus,Integer pageNo, Integer pageSize){
        Long totalCount = specRegisterMapper.getRegisterCount(clinicId,patientName,deptId,doctorId,visitDate,regStatus);
        if(StringUtil.isBlank(totalCount)){
            return PageInfo.build();
        }
        List<ClinicRegisterVo> registerList = listRegister(clinicId,patientName,deptId,doctorId,visitDate,regStatus,pageNo,pageSize);
        return new PageInfo<>(totalCount,registerList);
    }

    /**
     * 查询挂号列表
     * @param clinicId
     * @param patientName
     * @param deptId
     * @param visitDate
     * @param regStatus
     * @param pageNo
     * @param pageSize
     * @return
     */
    public List<ClinicRegisterVo> listRegister(Long clinicId,String patientName,Long deptId,Long doctorId,LocalDate visitDate,String regStatus,Integer pageNo, Integer pageSize){
        return specRegisterMapper.getRegisterList(clinicId,patientName,deptId,doctorId,visitDate,regStatus,PageUtils.getOffset(pageNo,pageSize),pageSize);
    }

    /**
     * 查询挂号统计
     * @param clinicId
     * @param patientName
     * @param deptId
     * @param doctorId
     * @param visitDate
     * @return
     */
    public StatClinicRegVo getRegisterStat(Long clinicId, String patientName, Long deptId, Long doctorId, LocalDate visitDate) {
        return specRegisterMapper.getStatReg(clinicId,patientName,deptId,doctorId,visitDate);
    }

    /**
     * 挂号-医生列表
     * @param clinicId
     * @param visitDate
     * @return
     */
    public List<DoctorRegisterDailyVo> getDoctorList(Long clinicId, LocalDate visitDate){
        return specRegisterMapper.getDoctorList(clinicId,visitDate);
    }

    /**
     * 挂号医生余号列表
     * @param clinicId
     * @param visitDate
     * @param doctorName
     * @return
     */
    public List<DeptRemainVo> getRemainList(Long clinicId,Long deptId,LocalDate visitDate,Long doctorId,String doctorName){
        List<String> regStatusList = RegStatusEnum.getReserveList();
        List<DeptRemainVo> remainList = specRegisterMapper.getRemainList(clinicId,deptId,doctorId,visitDate,doctorName,regStatusList);
        if(CollectionUtils.isEmpty(remainList)){
            return Collections.EMPTY_LIST;
        }
        for(DeptRemainVo clinicDeptRemainVo : remainList){
            List<DoctorRemainVo> doctorRemainList = clinicDeptRemainVo.getRemainList();
            if(CollectionUtils.isEmpty(doctorRemainList)){
                continue;
            }
            for(DoctorRemainVo doctorRemainVo : doctorRemainList){
                RegUtil.buildPeriodList(visitDate,doctorRemainVo);
            }
        }
        return remainList;
    }

    /**
     * 查询医生余号情况
     * @param clinicId 诊所
     * @param visitDate 就诊日期
     * @param doctorId 医生ID
     * @param visitPeriod 就诊时段
     * @return
     */
    public DoctorRemain getDoctorRemain(Long clinicId, LocalDate visitDate, Long doctorId, String visitPeriod){
        List<DeptRemainVo> remainList = getRemainList(clinicId,null,visitDate,doctorId,null);
        if(CollectionUtils.isEmpty(remainList)){
            return null;
        }
        DeptRemainVo deptRemainVo = remainList.get(0);
        if(deptRemainVo == null){
            return null;
        }
        DoctorRemainVo doctorRemainVo = deptRemainVo.getRemainList().get(0);
        if(deptRemainVo == null){
            return null;
        }
        DoctorRemain doctorRemainBo = new DoctorRemain();
        BeanUtils.copyProperties(doctorRemainVo,doctorRemainBo);
        List<DoctorRegPeriodVo> periodVoList = doctorRemainVo.getPeriodList();
        for(DoctorRegPeriodVo doctorRegPeriodVo : periodVoList){
            if(visitPeriod.equals(doctorRegPeriodVo.getValue())){
                doctorRemainBo.setRemainCount(doctorRegPeriodVo.getRemainCount());
                doctorRemainBo.setDetailList(doctorRegPeriodVo.getDetailList());
                return doctorRemainBo;
            }
        }
        return null;
    }

    /**
     * 添加挂号
     * @param clinicRegister 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public ClinicRegister addRegister(ClinicRegister clinicRegister) {
        validateRegister(clinicRegister);
        clinicRegister.setPayStatus(PayStatusEnum.ORDERED.getValue());
        clinicRegister.setVisitNo(RegUtil.getVisitNo(
                clinicRegister.getVisitDate(),
                clinicRegister.getClinicId(),
                clinicRegister.getDoctorId(),
                clinicRegister.getVisitPeriod(),
                clinicRegister.getVisitSeqNo()));
        clinicRegister.setIsDelete(YesOrNoEnum.NO.getValue());
        clinicRegister.setIsEnabled(YesOrNoEnum.YES.getValue());
        clinicRegister.setCreateTime(new Date());
        clinicRegisterMapper.insertSelective(clinicRegister);
        if(RegMethodEnum.REGISTER_ONSITE.getValue().equals(clinicRegister.getRegMethod())
            || (RegMethodEnum.REGISTER_APPOINTMENT.getValue().equals(clinicRegister.getRegMethod()) &&
                RegChannelEnum.OFFICE.getValue().equals(clinicRegister.getRegChannel()))){
            //如果是挂号或者是现场预约
            ChargeOrderBO chargeOrder = chargeOrderService.createRegisterOrder(clinicRegister);
            //生成缴费单成功回写到挂号单这样就可以在挂号直接支付了
            clinicRegister.setOrderId(chargeOrder.getOrderId());
            clinicRegister.setUpdateUserId(clinicRegister.getCreateUserId());
            clinicRegister.setUpdateBy(clinicRegister.getCreateBy());
            clinicRegister.setUpdateTime(new Date());
            clinicRegisterMapper.updateByPrimaryKeySelective(clinicRegister);
        }
        //统计诊所今日营收
        StatClinicIncomeDaily statClinicIncomeDaily = new StatClinicIncomeDaily();
        statClinicIncomeDaily.setClinicId(clinicRegister.getClinicId());
        statClinicIncomeDaily.setRegCount(CommonConstant.DEFAULT_1);
        asyncTaskService.asyncSaveOrUpdateClinicIncome(statClinicIncomeDaily);
        return clinicRegister;
    }


    /**
     * 校验挂号
     * @param register 实体
     */
    public void validateRegister(ClinicRegister register) {
        if (StringUtil.isBlank(register.getVisitPeriod())) {
            throw new BusinessFailException("请选择就诊时段");
        }
        if (!VisitPeriodEnum.isValue(register.getVisitPeriod())) {
            throw new BusinessFailException("就诊时段错误");
        }
        if (register.getDoctorId() == null) {
            throw new BusinessFailException("请选择要挂号的医生");
        }
        if (StringUtil.isBlank(register.getRegMethod())) {
            throw new BusinessFailException("挂号方式不能为空");
        }
        if (!RegMethodEnum.isValue(register.getRegMethod())) {
            throw new BusinessFailException("挂号方式错误");
        }
        if (StringUtil.isBlank(register.getRegChannel())) {
            throw new BusinessFailException("挂号渠道不能为空");
        }
        if (!RegChannelEnum.isValue(register.getRegChannel())) {
            throw new BusinessFailException("挂号渠道错误");
        }
        if (RegMethodEnum.REGISTER_ONSITE.getValue().equals(register.getRegMethod())) {
            if(RegChannelEnum.OFFICE.getValue().equals(register.getRegChannel())){
                register.setRegStatus(RegStatusEnum.PAID_NOT_TAKEN.getValue());
            }else {
                register.setRegStatus(RegStatusEnum.CHECK_IN.getValue());
            }
            if(!LocalDate.now().equals(register.getVisitDate())){
                throw new BusinessFailException("只能挂当天的号！");
            }
            //判断一下时段
            List<String> availablePeriodList = VisitPeriodEnum.getAvailablePeriods(LocalTime.now());
            if(!availablePeriodList.contains(register.getVisitPeriod())){
                throw new BusinessFailException("就诊时段错误只能选择当前及以后的时段！");
            }
        } else {
            if (register.getVisitDate() == null) {
                throw new BusinessFailException("请选择就诊日期");
            }
            if(StringUtil.isBlank(register.getVisitSeqNo())){
                throw new BusinessFailException("请选择需要预约的号段！");
            }
            register.setRegStatus(RegStatusEnum.RESERVED.getValue());
            //预约的都是初次、普通号
            register.setVisitType(VisitTypeEnum.FIRST_VISIT.getValue());
            register.setRegType(RegTypeEnum.NORMAL.getValue());
        }
        if (StringUtil.isBlank(register.getVisitType())) {
            register.setVisitType(VisitTypeEnum.FIRST_VISIT.getValue());
        }
        if (!VisitTypeEnum.isValue(register.getVisitType())) {
            throw new BusinessFailException("初诊类型错误");
        }
        if (StringUtil.isBlank(register.getRegType())) {
            register.setRegType(RegTypeEnum.NORMAL.getValue());
        }
        if (!RegTypeEnum.isValue(register.getRegType())) {
            throw new BusinessFailException("挂号类型错误");
        }
        if (StringUtil.isBlank(register.getPatientId())) {
            ClinicPatient patientInfo = new ClinicPatient();
            BeanUtils.copyProperties(register, patientInfo);
            patientInfo.setCreateUserId(register.getCreateUserId());
            patientInfo.setCreateBy(register.getCreateBy());
            ClinicPatient dbPatientInfo = patientService.addPatient(patientInfo);
            register.setPatientId(dbPatientInfo.getPatientId());
            if(register.getSolarBirthday() == null){
                register.setSolarBirthday(dbPatientInfo.getSolarBirthday());
            }
            if(register.getLunarBirthday() == null){
                register.setLunarBirthday(dbPatientInfo.getLunarBirthday());
            }
            if(StringUtil.isBlank(register.getAgeYear())){
                register.setAgeYear(dbPatientInfo.getAgeYear());
            }
            if(StringUtil.isBlank(register.getAgeMonth())){
                register.setAgeMonth(dbPatientInfo.getAgeMonth());
            }
            if(StringUtil.isBlank(register.getPatientGender())){
                register.setPatientGender(dbPatientInfo.getPatientGender());
            }
        } else {
            // 已传ID则校验并回填患者信息
            ClinicPatient patientInfo = patientService.getPatientById(register.getPatientId());
            if (patientInfo == null) {
                throw new BusinessFailException("患者不存在");
            }
            register.setPatientName(patientInfo.getPatientName());
            register.setPatientGender(patientInfo.getPatientGender());
            register.setPatientPhone(patientInfo.getPatientPhone());
            register.setIdCard(patientInfo.getIdCard());
            register.setAgeYear(patientInfo.getAgeYear());
            register.setAgeMonth(patientInfo.getAgeMonth());
            register.setSolarBirthday(patientInfo.getSolarBirthday());
            register.setLunarBirthday(patientInfo.getLunarBirthday());
            register.setWeight(patientInfo.getWeight());
            register.setSystolicBp(patientInfo.getSystolicBp());
            register.setDiastolicBp(patientInfo.getDiastolicBp());
        }
        Long regCount = getRegisterCountByPatientId(register.getClinicId(),register.getVisitDate(),register.getDoctorId(),register.getVisitPeriod(),register.getPatientId());
        if(regCount > CommonConstant.DEFAULT_0){
            throw new BusinessFailException("不允许重复挂号！");
        }
        // 查询医生余号
        DoctorRemain doctorRemain = getDoctorRemain(
                register.getClinicId(),
                register.getVisitDate(),
                register.getDoctorId(),
                register.getVisitPeriod()
        );
        if (doctorRemain == null) {
            throw new BusinessFailException("当前时段医生没有排班！");
        }
        if (RegMethodEnum.REGISTER_APPOINTMENT.getValue().equals(register.getRegMethod())) {
            if (doctorRemain.getRemainCount() <= CommonConstant.DEFAULT_0) {
                throw new BusinessFailException("暂无可预约号源！");
            }
        }
        register.setDoctorName(doctorRemain.getDoctorName());
        // 计算挂号费
        if (RegMethodEnum.REGISTER_ONSITE.getValue().equals(register.getRegMethod())) {
            //如果是挂号
            if (RegTypeEnum.EMERGENCY.getValue().equals(register.getRegType())) {
                //急诊直接用急诊费用
                register.setDoctorFee(doctorRemain.getEmergencyFee());
            } else {
                if (VisitTypeEnum.FIRST_VISIT.getValue().equals(register.getVisitType())) {
                    //初诊用初诊价格
                    register.setDoctorFee(doctorRemain.getFirstVisitFee());
                } else if (VisitTypeEnum.FOLLOW_UP.getValue().equals(register.getVisitType())) {
                    //复诊用复诊价格
                    register.setDoctorFee(doctorRemain.getFollowUpFee());
                }
            }
        } else {
            //如果是预约直接用预约费用
            register.setDoctorFee(doctorRemain.getAppointmentFee());
        }
        if(StringUtil.isBlank(register.getRegFee())){
            register.setRegFee(register.getDoctorFee());
        }
        // 分配号段
        List<DoctorRegPeriodDetailVo> detailList = doctorRemain.getDetailList();
        DoctorRegPeriodDetailVo targetDetail = null;
        if (StringUtil.isBlank(register.getVisitSeqNo())) {
            // 自动分配一个可用号段
            for (DoctorRegPeriodDetailVo detailVo : detailList) {
                if (YesOrNoEnum.YES.getValue().equals(detailVo.getAvailable())) {
                    targetDetail = detailVo;
                    break;
                }
            }
            if (targetDetail == null) {
                // 因为可以直接加号，所以挂号不能让选择号段
                //这里需要从数据库查询最大号然后+1
                targetDetail = detailList.get(detailList.size() - 1);
//                targetDetail.setVisitSeqNo(targetDetail.getVisitSeqNo() + 1);
                int maxSeqNo = getMaxSeqNo(register.getVisitDate(),register.getClinicId(),register.getDoctorId(),register.getVisitPeriod());
                targetDetail.setVisitSeqNo(maxSeqNo);
            }
        } else {
            // 用户传了号段，需要校验
            for (DoctorRegPeriodDetailVo detailVo : detailList) {
                if (register.getVisitSeqNo().equals(detailVo.getVisitSeqNo())) {
                    targetDetail = detailVo;
                    break;
                }
            }
            if (targetDetail == null) {
                throw new BusinessFailException("无效的号段");
            }
            if (YesOrNoEnum.NO.getValue().equals(targetDetail.getAvailable())) {
                throw new BusinessFailException("当前号段不可用，请选择其他号段！");
            }
            Long registerCount = getRegisterByPeriod(
                    register.getClinicId(),
                    register.getDoctorId(),
                    register.getVisitDate(),
                    register.getVisitPeriod(),
                    register.getVisitSeqNo()
            );
            if (registerCount > CommonConstant.DEFAULT_0) {
                throw new BusinessFailException("该时段已经有人预约了，请更换其他时段");
            }
        }
        // 回填号段信息
        register.setVisitSeqNo(targetDetail.getVisitSeqNo());
        register.setVisitShiftId(targetDetail.getShiftId());
        register.setVisitStartTime(targetDetail.getStartTime());
        register.setVisitEndTime(targetDetail.getEndTime());
        register.setDeptId(targetDetail.getDeptId());
        ClinicDept clinicDept = clinicDeptService.getEnabledClinicDeptById(targetDetail.getDeptId());
        if(clinicDept == null){
            throw new BusinessFailException("科室已停用，不允许挂号！");
        }
        register.setDeptName(clinicDept.getDeptName());
        register.setRoomId(targetDetail.getRoomId());
        ClinicDeptRoom clinicDeptRoom = clinicDeptService.getEnabledClinicRoomById(targetDetail.getRoomId());
        if(clinicDeptRoom == null){
            throw new BusinessFailException("诊室已停用，不允许挂号！");
        }
        register.setRoomName(clinicDeptRoom.getRoomName());
        if(StringUtil.isBlank(register.getSortNum())){
            register.setSortNum(CommonConstant.DEFAULT_1);
        }
    }

    /**
     * 获取最大的序列号
     * @param visitDate
     * @param clinicId
     * @param doctorId
     * @param visitPeriod
     * @return
     */
    public int getMaxSeqNo(LocalDate visitDate, Long clinicId, Long doctorId, String visitPeriod) {
        Integer maxSeqNo = specRegisterMapper.getMaxSeqNo(visitDate,clinicId,doctorId,visitPeriod);
        return maxSeqNo + 1;
    }

    /**
     * 查询当前时间是否存在还生效的号
     * @param clinicId
     * @param visitDate
     * @param doctorId
     * @param visitPeriod
     * @param patientId
     * @return
     */
    public Long getRegisterCountByPatientId(Long clinicId,LocalDate visitDate, Long doctorId,String visitPeriod, Long patientId) {
        ClinicRegisterExample example = new ClinicRegisterExample();
        ClinicRegisterExample.Criteria criteria = example.createCriteria();
        criteria.andClinicIdEqualTo(clinicId);
        criteria.andVisitDateEqualTo(visitDate);
        criteria.andVisitPeriodEqualTo(visitPeriod);
        criteria.andDoctorIdEqualTo(doctorId);
        criteria.andPatientIdEqualTo(patientId);
        criteria.andRegStatusIn(RegStatusEnum.getActiveList());
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        return clinicRegisterMapper.countByExample(example);
    }

    /**
     * 查询号段是否已经被人预约了
     * @param clinicId
     * @param doctorId
     * @param visitDate
     * @param visitPeriod
     * @param visitSeqNo
     * @return
     */
    public Long getRegisterByPeriod(Long clinicId,
                                              Long doctorId,
                                              LocalDate visitDate,
                                              String visitPeriod,
                                              Integer visitSeqNo){
        ClinicRegisterExample example = new ClinicRegisterExample();
        ClinicRegisterExample.Criteria criteria = example.createCriteria();
        criteria.andClinicIdEqualTo(clinicId);
        criteria.andDoctorIdEqualTo(doctorId);
        criteria.andVisitDateEqualTo(visitDate);
        criteria.andVisitPeriodEqualTo(visitPeriod);
        criteria.andVisitSeqNoEqualTo(visitSeqNo);
        criteria.andRegStatusIn(RegStatusEnum.getReserveList());
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        return clinicRegisterMapper.countByExample(example);
    }


    /**
     * 支付成功以后的逻辑
     * @param clinicRegister
     */
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(ClinicRegister clinicRegister){
        ClinicRegister dbClinicRegister = getRegisterById(clinicRegister.getRegisterId());
        if(dbClinicRegister == null){
            log.info("挂号费支付成功，没有找到挂号单:{}",clinicRegister);
            return;
        }
        if(PayStatusEnum.PAID.getValue().equals(dbClinicRegister.getPayStatus())){
            log.info("挂号费已经支付成功:{}",clinicRegister);
            return;
        }
        //1.修改挂号状态
        dbClinicRegister.setPayStatus(PayStatusEnum.PAID.getValue());
        dbClinicRegister.setPayChannel(clinicRegister.getPayChannel());
        dbClinicRegister.setUpdateUserId(clinicRegister.getUpdateUserId());
        dbClinicRegister.setUpdateBy(clinicRegister.getUpdateBy());
        updateRegister(dbClinicRegister);
        if(LocalDate.now().equals(dbClinicRegister.getVisitDate())){
            //挂号的直接发消息，预约取号的直接发消息，门诊室预约的并且直接支付的不在这里发签到消息
            autoCheckinProducer.submitDelaySeconds(clinicRegister.getRegisterId(),60);
        }
    }

    @Autowired
    private AutoCheckinProducer autoCheckinProducer;

    /**
     * 分页查询挂号
     * @param clinicId 诊所ID
     * @param pageNo 页码
     * @param pageSize 每页数量
     * @return 分页结果
     */
    public PageInfo<ClinicRegister> getRegisterListByCondition(Long clinicId,Integer pageNo, Integer pageSize) {
        ClinicRegisterExample example = new ClinicRegisterExample();
        ClinicRegisterExample.Criteria criteria = example.createCriteria();
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        Long totalCount = clinicRegisterMapper.countByExample(example);
        if (totalCount == null || totalCount == 0) {
            return PageInfo.build();
        }
        example.setOffset(PageUtils.getOffset(pageNo, pageSize));
        example.setLimit(pageSize);
        example.setOrderByClause("create_time desc");
        List<ClinicRegister> registerList = clinicRegisterMapper.selectByExample(example);
        return new PageInfo<>(totalCount, registerList);
    }

    /**
     * 根据主键查询挂号信息
     * @param registerId 主键ID
     * @return 实体
     */
    public ClinicRegister getRegisterById(Long registerId) {
        if (registerId == null) {
            return null;
        }
        ClinicRegister register = clinicRegisterMapper.selectByPrimaryKey(registerId);
        if (register == null || YesOrNoEnum.YES.getValue().equals(register.getIsDelete())) {
            return null;
        }
        return register;
    }


    /**
     * 修改挂号
     * @param clinicRegister 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateRegister(ClinicRegister clinicRegister) {
        ClinicRegister dbRegister = getRegisterById(clinicRegister.getRegisterId());
        if (dbRegister == null) {
            throw new BusinessFailException("挂号不存在");
        }
        clinicRegister.setUpdateTime(new Date());
        clinicRegisterMapper.updateByPrimaryKeySelective(clinicRegister);
    }


    /**
     * 删除挂号（逻辑删除）
     * @param clinicRegister 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteRegister(ClinicRegister clinicRegister) {
        ClinicRegister dbRegister = getRegisterById(clinicRegister.getRegisterId());
        if (dbRegister == null) {
            throw new BusinessFailException("挂号不存在");
        }
        dbRegister.setIsDelete(YesOrNoEnum.YES.getValue());
        dbRegister.setUpdateUserId(clinicRegister.getUpdateUserId());
        dbRegister.setUpdateBy(clinicRegister.getUpdateBy());
        dbRegister.setUpdateTime(new Date());
        clinicRegisterMapper.updateByPrimaryKeySelective(dbRegister);
    }

    /**
     * 启用挂号
     * @param clinicRegister 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void enableRegister(ClinicRegister clinicRegister) {
        ClinicRegister dbRegister = getRegisterById(clinicRegister.getRegisterId());
        if (dbRegister == null) {
            throw new BusinessFailException("挂号不存在");
        }
        if (YesOrNoEnum.YES.getValue().equals(dbRegister.getIsEnabled())) {
            return;
        }
        dbRegister.setIsEnabled(YesOrNoEnum.YES.getValue());
        dbRegister.setUpdateUserId(clinicRegister.getUpdateUserId());
        dbRegister.setUpdateBy(clinicRegister.getUpdateBy());
        dbRegister.setUpdateTime(new Date());
        clinicRegisterMapper.updateByPrimaryKeySelective(dbRegister);
    }

    /**
     * 停用挂号
     * @param clinicRegister 实体
     */
    @Transactional(rollbackFor = Exception.class)
    public void disableRegister(ClinicRegister clinicRegister) {
        ClinicRegister dbRegister = getRegisterById(clinicRegister.getRegisterId());
        if (dbRegister == null) {
            throw new BusinessFailException("挂号不存在");
        }
        if (YesOrNoEnum.NO.getValue().equals(dbRegister.getIsEnabled())) {
            return;
        }
        dbRegister.setIsEnabled(YesOrNoEnum.NO.getValue());
        dbRegister.setUpdateUserId(clinicRegister.getUpdateUserId());
        dbRegister.setUpdateBy(clinicRegister.getUpdateBy());
        dbRegister.setUpdateTime(new Date());
        clinicRegisterMapper.updateByPrimaryKeySelective(dbRegister);
    }

    /**
     * 小程序查询预约列表
     * @param clinicId
     * @param cmUserId
     * @param regStatus
     * @param pageNo
     * @param pageSize
     * @return
     */
    public List<ClinicRegisterVo> getAppointmentList(Long clinicId, Long cmUserId, String regStatus, Integer pageNo, Integer pageSize) {
        return specRegisterMapper.getAppointmentList(clinicId,cmUserId,regStatus, PageUtils.getOffset(pageNo,pageSize),pageSize);
    }

    /**
     * 根据诊号查询挂号信息
     * @param visitNo
     * @return
     */
    public ClinicRegister getRegisterByVisitNo(String visitNo) {
        ClinicRegisterExample example = new ClinicRegisterExample();
        ClinicRegisterExample.Criteria criteria = example.createCriteria();
        criteria.andVisitNoEqualTo(visitNo);
        criteria.andIsDeleteEqualTo(YesOrNoEnum.NO.getValue());
        List<ClinicRegister> registerList = clinicRegisterMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(registerList)){
            return null;
        }
        return registerList.get(0);
    }
}
